package edu.ccut.saturn.component.impl.node;

import java.util.ArrayList;
import java.util.List;

import edu.ccut.saturn.component.ComponentManager;
import edu.ccut.saturn.component.ILogicContext;
import edu.ccut.saturn.component.IParameterContext;
import edu.ccut.saturn.component.IParameterInfo;
import edu.ccut.saturn.component.SaturnDebugThreadsManager;
import edu.ccut.saturn.component.impl.SaturnParameterInfo;
import edu.ccut.saturn.component.loader.node.EndIterationNodeInfoLoader;
import edu.ccut.saturn.component.loader.node.NodeInfoLoader;
import edu.ccut.saturn.component.utils.ExceptionUtils;
import edu.ccut.saturn.component.xml.ISaturnElement;
import edu.ccut.saturn.component.xml.SaturnElement;

/**
 * 循环结束结点的实现类。在logic组件中被调用，表示循环体执行结束，并判断是否继续执行循环体内容。
 * <p>
 * <code>EndIteratorNodeInfo</code>继承了<code>AbstractNodeInfo</code>,扩展的字段如下：
 * 
 * <li>字段<code>startId</code>：记录了与循环结束结点相对应的循环开始结点的id；
 * <li>字段<code>iteratorHasNextId</code>：记录了在上下文中保存了是否继续执行循环的变量的变量名称。
 * 
 * @author 谷钰
 * @author 温建
 * 
 * @version 1.0 2008.8.19
 * 
 * @see AbstractNodeInfo
 * @see ILogicContext
 * 
 */
public class EndIteratorNodeInfo extends AbstractNodeInfo {

	private static final String ITERATION_HAS_NEXT = "__ITERATOR_HAS_NEXT__";

	private String startId;

	private String iteratorHasNextId;

	public EndIteratorNodeInfo(String id, String name, String description,
			String nextId, String startId, String x, String y) {

		super(id, name, description, nextId, null, x, y, "end-iteration");
		this.startId = startId;
		this.iteratorHasNextId = startId + ITERATION_HAS_NEXT;
	}

	/**
	 * 循环结束结点的执行逻辑。
	 * 从上下文中获取是否继续执行循环的变量的值；如果这个值是”true“则下一个运行结点就是与这个循环结束结点相对应的循环开始结点；
	 * 如果这个值为空或不为”true“，则下一个结点就是这个结点的nextId字段保存的结点id。
	 * 
	 * @param logicContext
	 *            逻辑上下文对象，记录结点运行时的上下文信息
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void doExecute(ILogicContext logicContext) throws Exception {
		ComponentManager.beforeExecuteComponent(this, this
				.createParameterContext(logicContext));

		try {
			Object isContinue = logicContext.getValue(this.iteratorHasNextId);

			if (isContinue != null) {

				if ("true".equals(isContinue)) {
					logicContext.setNodeRouter(getId(), startId);
				}
			}
			logger.debug("      node : {execute : '{result : '" + ("true".equals(isContinue) ? " over iterator"
							: " continue itartor") + "'}', process : '" + logicContext.getId() + "'}");

		} catch (Exception e) {
			logger.error("ERROR : {message : '" + ExceptionUtils.getExMessage(e) + "', process : '" + logicContext.getId() + "', node : '"
					+ super.getNodeType() + " " + super.getId() + " " + super.getName() + "'}" );
			throw e;
			
		} finally {
			ComponentManager.afterExecuteComponent(this, this
					.createParameterContext(logicContext));
		}
	}

	/**
	 * 获得与循环结束结点对应的循环开始结点的id
	 * 
	 * @return
	 */
	public String getStartId() {
		return startId;
	}

	/**
	 * 设置与循环结束结点对应的循环开始结点的id
	 * 
	 * @param expr
	 */
	public void setStartId(String startId) {
		this.startId = startId;
	}

	protected IParameterContext createParameterContext(
			ILogicContext logicContext) throws Exception {

		if (SaturnDebugThreadsManager.getInstance().isStart()) {
			initParameterInfos();
			return logicContext.createParameterContext(getParameterInfos());
		}
		return null;
	}

	private void initParameterInfos() {
		List<IParameterInfo> parameters = new ArrayList<IParameterInfo>();
		SaturnParameterInfo isContinueParameter = new SaturnParameterInfo();
		isContinueParameter.setClassType(String.class);
		isContinueParameter.setId("1");
		isContinueParameter.setName("has_next");
		isContinueParameter.setPassingType(IParameterInfo.PASSING_IN);
		isContinueParameter.setScope(IParameterInfo.SCOPE_LOGIC);
		isContinueParameter.setValueKey(this.iteratorHasNextId);
		parameters.add(isContinueParameter);
		super.setParameterInfos(parameters);
	}

	public ISaturnElement toSaturnElement() {
		ISaturnElement endIteratorElement = new SaturnElement(
				EndIterationNodeInfoLoader.KEY_NODETYPE_ITERATION_END);

		endIteratorElement.addAttribute(NodeInfoLoader.KEY_NODE_ID, this
				.getId());

		endIteratorElement.addAttribute(NodeInfoLoader.KEY_NODE_NEXT, this
				.getNextId());

		endIteratorElement.addAttribute(NodeInfoLoader.KEY_NODE_X, this.getX());
		endIteratorElement.addAttribute(NodeInfoLoader.KEY_NODE_Y, this.getY());

		ISaturnElement nameElement = new SaturnElement(
				NodeInfoLoader.KEY_NODE_NAME, this.getName());

		ISaturnElement descriptionElement = new SaturnElement(
				NodeInfoLoader.KEY_NODE_DESCRIPTION, this.getDescription());

		ISaturnElement startIdElement = new SaturnElement(
				EndIterationNodeInfoLoader.KEY_ITERATION_START_ID, this.startId);

		endIteratorElement.addSubElement(nameElement);
		endIteratorElement.addSubElement(descriptionElement);
		endIteratorElement.addSubElement(startIdElement);
		return endIteratorElement;
	}

}